로딩 중이에요... 🐣
[코담]
웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트
08 단위 테스트(TestCase) 작성 및 실행 | ✅ 편저: 코담 운영자
Django 웹 프로그래밍 강좌 8강 - 단위 테스트(TestCase) 작성 및 실행 (Django 5.2 기준)
이 강의는 Django 공식 문서의 2.2 튜토리얼 내용을 바탕으로 진행되며, Django 5.2 버전에 맞춰 테스트 관련 기능들을 실습 중심으로 설명합니다.
📚 공식문서 주소: https://docs.djangoproject.com/ko/5.2/intro/tutorial05/
1. 테스트란?
테스트(Test)는 코드가 예상대로 동작하는지 확인하는 자동화된 검증 절차입니다. Django는 unittest
모듈을 기반으로 한 TestCase
클래스를 통해 테스트를 지원합니다.
테스트의 주요 목적:
- 코드 변경으로 인한 버그를 조기에 발견
- 협업 환경에서 안정성 확보
- 개발 생산성 향상 및 리팩토링 안정성 확보
테스트 코드는 문서보다 신뢰할 수 있는 코드의 실행 보증 수단입니다.
2. 테스트 작성 위치 및 규칙
- 테스트 파일명은
test_*.py
형식 - 앱 디렉토리 내부 (예:
polls/tests.py
) - 클래스명은
Test*
, 메서드명은test_
로 시작해야 Django가 테스트로 인식합니다
테스트 실행 명령어:
python manage.py test
- 해당 명령어는 프로젝트 내 모든 앱의 테스트를 자동 탐색 및 실행합니다
- 각 테스트의 성공/실패 여부가 콘솔에 출력됩니다
3. 모델 메서드 테스트 예시
Question.was_published_recently()
메서드에 대한 테스트를 작성해봅니다.
polls/tests.py
import datetime
from django.utils import timezone
from django.test import TestCase
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
- 미래 날짜의 질문은
was_published_recently()
결과가False
여야 합니다 assertIs()
는 기대한 값과 실제 값이 같은지를 검사합니다
테스트 실패 시 어떤 조건에서 실패했는지 상세 로그가 출력되어 디버깅에 유리합니다
4. View 테스트: 클라이언트 시뮬레이션
Django의 테스트 클라이언트는 실제 사용자가 브라우저를 통해 요청을 보내는 것처럼 작동합니다.
테스트 예시:
from django.urls import reverse
from .models import Question
from django.utils import timezone
class QuestionIndexViewTests(TestCase):
def test_no_questions(self):
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerySetEqual(response.context["latest_question_list"], [])
self.client.get(...)
: 가상의 GET 요청 실행assertContains()
: 응답 본문에 특정 텍스트가 포함되어 있는지 검사assertQuerySetEqual()
: 응답에 포함된 쿼리셋이 예상과 일치하는지 확인
5. 테스트 유틸 함수와 시간 조건 필터링
뷰에서 미래 시점의 게시물은 노출되지 않아야 함. 따라서 시간 조건에 따른 테스트도 필요합니다.
헬퍼 함수로 테스트 데이터 생성
def create_question(question_text, days):
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
- days > 0: 미래 게시물, days < 0: 과거 게시물
다양한 조건에 대한 테스트 작성
class QuestionIndexViewTests(TestCase):
def test_past_question(self):
question = create_question("Past question", -30)
response = self.client.get(reverse("polls:index"))
self.assertContains(response, question.question_text)
def test_future_question(self):
create_question("Future question", 30)
response = self.client.get(reverse("polls:index"))
self.assertContains(response, "No polls are available.")
self.assertQuerySetEqual(response.context["latest_question_list"], [])
- 미래 질문은 리스트에 노출되지 않아야 하며, 테스트로 이 조건을 보장할 수 있습니다
6. 테스트가 중요한 이유 정리
- 테스트는 코드 안정성과 협업 효율성을 동시에 확보할 수 있는 도구입니다
- 코드 변경 시 문제를 빠르게 발견할 수 있어 유지보수가 쉬워집니다
- 테스트가 통과하면 해당 기능이 정상 작동한다는 확신을 줄 수 있습니다
- CI/CD 파이프라인과도 쉽게 통합되어 자동 검증이 가능합니다
마무리 요약
- Django는
unittest
기반의 테스트 프레임워크를 기본 제공 TestCase
를 상속받아 모델/뷰 테스트 가능- 클라이언트 시뮬레이션을 통한 실제 요청 테스트가 가능함
- 시간 조건, 예외 조건 등 다양한 상황을 테스트할 수 있음
- 테스트는 코드의 신뢰성과 안정성을 확보하는 핵심 도구
다음 강의 예고
9강에서는 CSS 및 static 파일 연결을 통해 정적인 디자인 리소스를 Django에 적용하는 방법을 학습합니다.
감사합니다.